home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / utils / browse-url.el.z / browse-url.el
Encoding:
Text File  |  1998-05-21  |  30.3 KB  |  869 lines

  1. ;;; browse-url.el --- ask a WWW browser to load a URL
  2.  
  3. ;; Copyright 1995 Free Software Foundation, Inc.
  4.  
  5. ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
  6. ;; Maintainer: Denis Howe <dbh@doc.ic.ac.uk>
  7. ;; Created: 03 Apr 1995
  8. ;; Version: 0.38 18 Jun 1996
  9. ;; Keywords: hypertext
  10. ;; X-Home page: http://wombat.doc.ic.ac.uk/
  11.  
  12. ;; This file is part of XEmacs.
  13.  
  14. ;; XEmacs is free software; you can redistribute it and/or modify it
  15. ;; under the terms of the GNU General Public License as published by
  16. ;; the Free Software Foundation; either version 1, or (at your option)
  17. ;; any later version.
  18.  
  19. ;; XEmacs is distributed in the hope that it will be useful, but
  20. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  21. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  22. ;; General Public License for more details.
  23.  
  24. ;; You should have received a copy of the GNU General Public License
  25. ;; along with XEmacs; see the file COPYING.  If not, write to the Free
  26. ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  27. ;; 02111-1307, USA.
  28.  
  29. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  30. ;;; Commentary:
  31.  
  32. ;; The latest version of this package should be available from
  33. ;; <URL:http://wombat.doc.ic.ac.uk/emacs/browse-url.el>.
  34.  
  35. ;; This package provides functions which read a URL (Uniform Resource
  36. ;; Locator) from the minibuffer, defaulting to the URL around point,
  37. ;; and ask a World-Wide Web browser to load it.  It can also load the
  38. ;; URL associated with the current buffer.  Different browsers use
  39. ;; different methods of remote control so there is one function for
  40. ;; each supported browser.  If the chosen browser is not running, it
  41. ;; is started.  Currently there is support for:
  42.  
  43. ;; Function              Browser     Earliest version
  44. ;; browse-url-netscape   Netscape    1.1b1       
  45. ;; browse-url-mosaic     XMosaic     <= 2.4
  46. ;; browse-url-cci        XMosaic     2.5
  47. ;; browse-url-w3         w3          0
  48. ;; browse-url-iximosaic  IXI Mosaic  ?
  49. ;; browse-url-lynx-*     Lynx         0
  50. ;; browse-url-grail      Grail       0.3b1
  51.  
  52. ;; Note that versions of Netscape before 1.1b1 did not have remote
  53. ;; control.  <URL:http://www.netscape.com/newsref/std/x-remote.html>
  54. ;; and <URL:http://www.netscape.com/info/APIs/>.
  55.  
  56. ;; Netscape can cache Web pages so it may be necessary to tell it to
  57. ;; reload the current page if it has changed (e.g. if you have edited
  58. ;; it).  There is currently no perfect automatic solution to this.
  59.  
  60. ;; Netscape allows you to specify the id of the window you want to
  61. ;; control but which window DO you want to control and how do you
  62. ;; discover its id?
  63.  
  64. ;; If using XMosaic before version 2.5, check the definition of
  65. ;; browse-url-usr1-signal below.
  66. ;; <URL:http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/remote-control.html>
  67.  
  68. ;; XMosaic version 2.5 introduced Common Client Interface allowing you
  69. ;; to control mosaic through Unix sockets.
  70. ;; <URL:http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/CCI/cci-spec.html>
  71.  
  72. ;; William M. Perry's excellent "w3" WWW browser for
  73. ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
  74. ;; has a function w3-follow-url-at-point, but that
  75. ;; doesn't let you edit the URL like browse-url.
  76.  
  77. ;; I recommend Nelson Minar <nelson@santafe.edu>'s excellent
  78. ;; html-helper-mode.el for editing HTML and thank Nelson for
  79. ;; his many useful comments on this code.
  80. ;; <URL:http://www.santafe.edu/~nelson/hhm-beta/>
  81.  
  82. ;; This package generalises function html-previewer-process in Marc
  83. ;; Andreessen <marca@ncsa.uiuc.edu>'s html-mode (LCD
  84. ;; modes/html-mode.el.Z) and provides better versions of the URL
  85. ;; functions in Michelangelo Grigni <mic@cs.ucsd.edu>'s ffap.el
  86. ;; (find-file-at-point) <URL:ftp://cs.ucsd.edu:/pub/mic/>.  The huge
  87. ;; hyperbole package also contains similar functions.
  88.  
  89. ;; Grail is the freely available WWW browser implemented in Python, a
  90. ;; cool object-oriented freely available interpreted language.  Grail
  91. ;; 0.3b1 was the first version to have remote control as distributed.
  92. ;; For more information on Grail see
  93. ;; <URL:http://monty.cnri.reston.va.us/> and for more information on
  94. ;; Python see <url:http://www.python.org/>.  Grail support in
  95. ;; browse-url.el written by Barry Warsaw <bwarsaw@python.org>.
  96.  
  97. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  98. ;; Help!
  99.  
  100. ;; Can you write and test some code for the Macintrash and Windoze
  101. ;; Netscape remote control APIs?  (See the URL above).
  102.  
  103. ;; Do any other browsers have remote control?
  104.  
  105. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  106. ;; Installation
  107.  
  108. ;; Put the following in your ~/.emacs file:
  109. ;;
  110. ;; (autoload 'browse-url-at-point "browse-url"
  111. ;;   "Ask a WWW browser to load the URL at or before point." t)
  112. ;; (autoload 'browse-url-at-mouse "browse-url"
  113. ;;   "Ask a WWW browser to load a URL clicked with the mouse." t)
  114. ;; (autoload 'browse-url-of-buffer "browse-url"
  115. ;;   "Ask a WWW browser to display BUFFER." t)
  116. ;; (autoload 'browse-url-of-file "browse-url"
  117. ;;   "Ask a WWW browser to display FILE." t)
  118. ;; (autoload 'browse-url-of-dired-file "browse-url"
  119. ;;   "In Dired, ask a WWW browser to display the file named on this line." t)
  120.  
  121. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  122. ;; Usage
  123.  
  124. ;; To display the URL at or before point:
  125. ;; M-x browse-url-at-point RET
  126.  
  127. ;; To display a URL by shift-clicking on it, put this in your ~/.emacs
  128. ;; file:
  129. ;;    (global-set-key [S-mouse-1] 'browse-url-at-mouse)
  130.  
  131. ;; To display the current buffer in a web browser:
  132. ;; M-x browse-url-of-buffer RET
  133.  
  134. ;; In Dired, to display the file named on the current line:
  135. ;; M-x browse-url-of-dired-file RET
  136.  
  137. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  138. ;; Customisation (~/.emacs)
  139.  
  140. ;; To see what variables are available for customization, type
  141. ;; `M-x set-variable browse-url TAB'.
  142.  
  143. ;; Bind the browse-url commands to keys with the `C-c C-z' prefix
  144. ;; (as used by html-helper-mode):
  145. ;;    (global-set-key "\C-c\C-z." 'browse-url-at-point)
  146. ;;    (global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
  147. ;;    (global-set-key "\C-c\C-zu" 'browse-url)
  148. ;;    (global-set-key "\C-c\C-zv" 'browse-url-of-file)
  149. ;;    (add-hook 'dired-mode-hook
  150. ;;          (function (lambda ()
  151. ;;                  (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file))))
  152.  
  153. ;; Browse URLs in mail messages by clicking mouse-2:
  154. ;;    (add-hook 'rmail-mode-hook (function (lambda () ; rmail-mode startup
  155. ;;      (define-key rmail-mode-map [mouse-2] 'browse-url-at-mouse))))
  156.  
  157. ;; Browse URLs in Usenet messages by clicking mouse-2:
  158. ;;    (eval-after-load "gnus"
  159. ;;      '(define-key gnus-article-mode-map [mouse-2] 'browse-url-at-mouse))
  160.  
  161. ;; Use the Emacs w3 browser when not running under X11:
  162. ;;    (or (eq window-system 'x)
  163. ;;        (setq browse-url-browser-function 'browse-url-w3))
  164.  
  165. ;; To always save modified buffers before displaying the file in a browser:
  166. ;;    (setq browse-url-save-file t)
  167.  
  168. ;; To get round the Netscape caching problem, you could EITHER have
  169. ;; write-file in html-helper-mode make Netscape reload the document:
  170. ;;
  171. ;;    (autoload 'browse-url-netscape-reload "browse-url"
  172. ;;      "Ask a WWW browser to redisplay the current file." t)
  173. ;;    (add-hook 'html-helper-mode-hook
  174. ;;          (function (lambda ()
  175. ;;             (add-hook 'local-write-file-hooks
  176. ;;                   (function (lambda ()
  177. ;;                  (let ((local-write-file-hooks))
  178. ;;                    (save-buffer))
  179. ;;                  (browse-url-netscape-reload)
  180. ;;                  t))            ; => file written by hook
  181. ;;                   t))))            ; append to l-w-f-hooks
  182. ;;
  183. ;; OR have browse-url-of-file ask Netscape to load and then reload the
  184. ;; file:
  185. ;;
  186. ;;    (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
  187.  
  188. ;; You may also want to customise browse-url-netscape-arguments, e.g.
  189. ;;    (setq browse-url-netscape-arguments '("-install"))
  190. ;;
  191. ;; or similarly for mosaic. 
  192.  
  193. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  194. ;;; Change Log:
  195.  
  196. ;; 0.00 03 Apr 1995 Denis Howe <dbh@doc.ic.ac.uk>
  197. ;;    Created.
  198.  
  199. ;; 0.01 04 Apr 1995
  200. ;;    All names start with "browse-url-".  Added provide.
  201.  
  202. ;; 0.02 05 Apr 1995
  203. ;;    Save file at start of browse-url-of-file.
  204. ;;    Use start-process instead of start-process-shell-command.
  205.  
  206. ;; 0.03 06 Apr 1995
  207. ;;    Add browse-url-netscape-reload, browse-url-netscape-send.
  208. ;;    browse-url-of-file save file option.
  209.  
  210. ;; 0.04 08 Apr 1995
  211. ;;    b-u-file-url separate function.  Change b-u-filename-alist
  212. ;;    default.
  213.  
  214. ;; 0.05 09 Apr 1995
  215. ;;    Added b-u-of-file-hook.
  216.  
  217. ;; 0.06 11 Apr 1995
  218. ;;    Improved .emacs suggestions and documentation.
  219.  
  220. ;; 0.07 13 Apr 1995
  221. ;;    Added browse-url-interactive-arg optional prompt.
  222.  
  223. ;; 0.08 18 Apr 1995
  224. ;;    Exclude final "." from browse-url-regexp.
  225.  
  226. ;; 0.09 21 Apr 1995
  227. ;;    Added mouse-set-point to browse-url-interactive-arg.
  228.  
  229. ;; 0.10 24 Apr 1995
  230. ;;    Added Mosaic signal sending variations.
  231. ;;    Thanks Brian K Servis <servis@ecn.purdue.edu>.
  232. ;;    Don't use xprop for Netscape.
  233.  
  234. ;; 0.11 25 Apr 1995
  235. ;;    Fix reading of ~/.mosaicpid.  Thanks Dag.H.Wanvik@kvatro.no.
  236.  
  237. ;; 0.12 27 Apr 1995
  238. ;;    Interactive prefix arg => URL *after* point.
  239. ;;    Thanks Michelangelo Grigni <mic@cs.ucsd.edu>.
  240. ;;    Added IXI Mosaic support.
  241. ;;    Thanks David Karr <dkarr@nmo.gtegsc.com>.
  242.  
  243. ;; 0.13 28 Apr 1995
  244. ;;    Exclude final [,;] from browse-url-regexp.
  245.  
  246. ;; 0.14 02 May 1995
  247. ;;    Provide browser argument variables.
  248.  
  249. ;; 0.15 07 May 1995
  250. ;;    More Netscape options.  Thanks Peter Arius
  251. ;;    <arius@immd2.informatik.uni-erlangen.de>.
  252.  
  253. ;; 0.16 17 May 1995
  254. ;;    Added browse-url-at-mouse.
  255. ;;    Thanks Wayne Mesard <wmesard@sgi.com>
  256.  
  257. ;; 0.17 27 Jun 1995
  258. ;;    Renamed browse-url-at-point to browse-url-url-at-point.
  259. ;;    Added browse-url-at-point.
  260. ;;    Thanks Jonathan Cano <cano@patch.tandem.com>.
  261.  
  262. ;; 0.18 16 Aug 1995
  263. ;;    Fixed call to browse-url-url-at-point in browse-url-at-point.
  264. ;;    Thanks Eric Ding <ericding@San-Jose.ate.slb.com>.
  265.  
  266. ;; 0.19 24 Aug 1995
  267. ;;    Improved documentation.
  268. ;;    Thanks Kevin Rodgers <kevin.rodgers@ihs.com>.
  269.  
  270. ;; 0.20 31 Aug 1995
  271. ;;    browse-url-of-buffer to handle file-less buffers.
  272. ;;    browse-url-of-dired-file browses current file in dired.
  273. ;;    Thanks Kevin Rodgers <kevin.rodgers@ihs.com>.
  274.  
  275. ;; 0.21 09 Sep 1995
  276. ;;    XMosaic CCI functions.
  277. ;;    Thanks Marc Furrer <Marc.Furrer@di.epfl.ch>.
  278.  
  279. ;; 0.22 13 Sep 1995
  280. ;;    Fixed new-window documentation and added to browse-url-cci.
  281. ;;    Thanks Dilip Sequeira <djs@dcs.ed.ac.uk>.
  282.  
  283. ;; 0.23 10 Nov 1995
  284. ;;    Added b-u-lynx.  Thanks Steven L. Baur <steve@miranova.com>.
  285.  
  286. ;; 0.24 22 Nov 1995
  287. ;;    Renamed b-u-netscape command to b-u-netscape-send.
  288. ;;    Added b-u-netscape-command variable.
  289.  
  290. ;; 0.25 03 Dec 1995
  291. ;;    Added event-buffer and event-point for XEmacs compatibility.
  292. ;;    Thanks Eric Engstrom <engstrom@src.honeywell.com>
  293.  
  294. ;; 0.26 13 Jan 1996
  295. ;;    Changed b-u-lynx to b-u-lynx-xterm, added b-u-lynx-emacs to
  296. ;;    run Lynx in an Emacs buffer under terminal-emulator.
  297. ;;    Thanks Jari Aalto <jaalto@tre.tele.nokia.fi>
  298.  
  299. ;; 0.27 27 Feb 1996
  300. ;;    Changed event-buffer and event-point from macros to functions.
  301. ;;    Other fixes for byte-compilation.
  302.  
  303. ;; 0.28 07 Mar 1996
  304. ;;    browse-url-lynx-emacs uses term.el instead of terminal.el.
  305.  
  306. ;; 0.29 13 Mar 1996
  307. ;;    Added browse-url-CCI-host.  Thanks Greg Marr <gregm@WPI.EDU>.
  308.  
  309. ;; 0.30 23 Mar 1996
  310. ;;    Contact/start Netscape in the background.
  311. ;;    Thanks Per Abrahamsen <abraham@dina.kvl.dk>
  312.  
  313. ;; 0.31 28 Apr 1996
  314. ;;    Added browse-url command.
  315. ;;    Added new-window logic to b-u-interactive-arg.
  316. ;;    b-u-file-url checks for EFS path.
  317.  
  318. ;; 0.32 02 May 1996
  319. ;;    Improved b-u-url-at-point matching to supply missing "http://".
  320.  
  321. ;; 0.33 01 Jun 1996
  322. ;;    Jari Aalto <jaalto@tre.tele.nokia.fi> browse-url-lynx-emacs
  323. ;;    fix.  Thanks Jari.
  324.  
  325. ;; 0.34 05 Jun 1996
  326. ;;    b-u-file-url checks for EFS after alist.  Thanks
  327. ;;    Jens-U H Petersen <petersen@kurims.kyoto-u.ac.jp>
  328.  
  329. ;; 0.35 11 Jun 1996
  330. ;;    Grail support.  Thanks Barry A. Warsaw
  331. ;;    <bwarsaw@anthem.cnri.reston.va.us>.
  332.  
  333. ;; 0.36 12 Jun 1996
  334. ;;    Fixed browse-url-looking-at (I hope).
  335.  
  336. ;; 0.37 15 Jun 1996
  337. ;;    b-u-file-url URL-encodes special chars.
  338. ;;    Thanks Martin Schwenke <Martin.Schwenke@cs.anu.edu.au>.
  339.  
  340. ;; 0.38 17 Jun 1996
  341. ;;    b-u-file-url encodes fewer chars.  Multi-display support for
  342. ;;    Netscape.  Thanks Richard Mlynarik <mly@adoc.xerox.com>
  343.  
  344. ;;; Code:
  345.  
  346. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  347. ;; Variables
  348.  
  349. (eval-when-compile (require 'dired))
  350.  
  351. (defgroup browse-url nil
  352.   "Ask a WWW browser to load a URL."
  353.   :group 'hypermedia)
  354.  
  355.  
  356. (defvar browse-url-path-regexp
  357.   "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+"
  358.   "A regular expression probably matching the host, path or e-mail
  359. part of a URL.")
  360.  
  361. (defvar browse-url-short-regexp
  362.   (concat "[-A-Za-z0-9.]+" browse-url-path-regexp)
  363.   "A regular expression probably matching a URL without an access scheme.
  364. Hostname matching is stricter in this case than for
  365. ``browse-url-regexp''.")
  366.  
  367. (defvar browse-url-regexp
  368.   (concat
  369.    "\\(https?://\\|ftp://\\|gopher://\\|telnet://\\|wais://\\|file:/\\|s?news:\\|mailto:\\)"
  370.    browse-url-path-regexp)
  371.   "A regular expression probably matching a complete URL.")
  372.  
  373.  
  374. ;;;###autoload
  375. (defcustom browse-url-browser-function 'browse-url-w3
  376.   "*Function to display the current buffer in a WWW browser.
  377. Used by the `browse-url-at-point', `browse-url-at-mouse', and
  378. `browse-url-of-file' commands."
  379.   :type '(radio (function-item browse-url-w3)
  380.         (function-item browse-url-netscape)
  381.         (function-item browse-url-mosaic)
  382.         (function-item browse-url-cci)
  383.         (function-item browse-url-iximosaic)
  384.         (function-item browse-url-lynx-xterm)
  385.         (function-item browse-url-lynx-emacs)
  386.         (function-item browse-url-grail)
  387.         (function :tag "Other" nil))
  388.   :group 'browse-url)
  389.  
  390. (defcustom browse-url-netscape-command "netscape"
  391.   "*The name by which to invoke Netscape."
  392.   :type 'string
  393.   :group 'browse-url)
  394.  
  395. (defcustom browse-url-netscape-arguments nil
  396.   "*A list of strings to pass to Netscape as arguments."
  397.   :type '(repeat (string :tag "Argument"))
  398.   :group 'browse-url)
  399.  
  400. (defcustom browse-url-new-window-p nil
  401.   "*If non-nil, always open a new browser window.
  402. Passing an interactive argument to \\[browse-url-netscape] or
  403. \\[browse-url-cci] reverses the effect of this variable.  Requires
  404. Netscape version 1.1N or later or XMosaic version 2.5 or later."
  405.   :type 'boolean
  406.   :group 'browse-url)
  407.  
  408. (defcustom browse-url-mosaic-arguments nil
  409.   "*A list of strings to pass to Mosaic as arguments."
  410.   :type '(repeat (string :tag "Argument"))
  411.   :group 'browse-url)
  412.  
  413. (defvar browse-url-filename-alist
  414.   '(("^/+" . "file:/"))
  415.   "An alist of (REGEXP . STRING) pairs.
  416. Any substring of a filename matching one of the REGEXPs is replaced by
  417. the corresponding STRING.  All pairs are applied in the order given.
  418. The default value prepends `file:' to any path beginning with `/'.
  419. Used by the `browse-url-of-file' command.")
  420.  
  421. (defvar browse-url-save-file nil
  422.   "If non-nil, save the buffer before displaying its file.
  423. Used by the `browse-url-of-file' command.")
  424.  
  425. (defvar browse-url-of-file-hook nil
  426.   "A hook to be run with run-hook after `browse-url-of-file' has asked
  427. a browser to load a file.
  428.  
  429. Set this to `browse-url-netscape-reload' to force Netscape to load the
  430. file rather than displaying a cached copy.")
  431.  
  432. (defvar browse-url-usr1-signal
  433.   (if (and (boundp 'emacs-major-version)
  434.        (or (> emacs-major-version 19) (>= emacs-minor-version 29)))
  435.       'SIGUSR1 ; Why did I think this was in lower case before?
  436.     30)                    ; Check /usr/include/signal.h.
  437.   "The argument to `signal-process' for sending SIGUSR1 to XMosaic.
  438. Emacs 19.29 accepts 'SIGUSR1, earlier versions require an integer
  439. which is 30 on SunOS and 16 on HP-UX and Solaris.")
  440.  
  441. (defvar browse-url-CCI-port 3003
  442.   "Port to access XMosaic via CCI.
  443. This can be any number between 1024 and 65535 but must correspond to
  444. the value set in the browser.")
  445.  
  446. (defvar browse-url-CCI-host "localhost"
  447.   "*Host to access XMosaic via CCI.
  448. This should be the host name of the machine running XMosaic with CCI
  449. enabled.  The port number should be set in `browse-url-CCI-port'.")
  450.  
  451. (defvar browse-url-temp-file-name nil)
  452. (make-variable-buffer-local 'browse-url-temp-file-name)
  453.  
  454. (defvar browse-url-temp-file-list '())
  455.  
  456. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  457. ;; URL input
  458.  
  459. ;; thingatpt.el doesn't work for complex regexps
  460.  
  461. (defun browse-url-url-at-point ()
  462.   "Return the URL around or before point.
  463. Search backwards for the start of a URL ending at or after 
  464. point.  If no URL found, return the empty string.  The
  465. access scheme, `http://' will be prepended if absent."
  466.   (cond ((browse-url-looking-at browse-url-regexp)
  467.      (buffer-substring (match-beginning 0) (match-end 0)))
  468.     ;; Access scheme omitted?
  469.     ((browse-url-looking-at browse-url-short-regexp)
  470.      (concat "http://"
  471.          (buffer-substring (match-beginning 0) (match-end 0))))
  472.     (t "")))            ; No match
  473.  
  474. (defun browse-url-looking-at (regexp)
  475.   "Return non-nil if point is in or just after a match for REGEXP.
  476. Set the match data from the earliest such match in the current line
  477. ending at or after point."
  478.   (save-excursion
  479.     (let ((old-point (point))
  480.       (eol (progn (end-of-line) (point)))
  481.       (hit nil))
  482.       (beginning-of-line)
  483.       (or (and (looking-at regexp)
  484.            (>= (match-end 0) old-point))
  485.       (progn
  486.         (while (and (re-search-forward regexp eol t)
  487.             (<= (match-beginning 0) old-point)
  488.             (not (setq hit (>= (match-end 0) old-point)))))
  489.         hit)))))
  490.  
  491. ;; Having this as a separate function called by the browser-specific
  492. ;; functions allows them to be stand-alone commands, making it easier
  493. ;; to switch between browsers.
  494.  
  495. (defun browse-url-interactive-arg (prompt)
  496.   "Read a URL from the minibuffer, prompting with PROMPT.
  497. Default to the URL at or before point.  If invoke with a mouse button,
  498. set point to the position clicked first.  Return a list for use in
  499. `interactive' containing the URL and browse-url-new-window-p or its
  500. negation if a prefix argument was given."
  501.   (let ((event (elt (this-command-keys) 0)))
  502.     (and (listp event) (mouse-set-point event)))
  503.   (list (read-string prompt (browse-url-url-at-point))
  504.     (not (eq (null browse-url-new-window-p)
  505.          (null current-prefix-arg)))))
  506.  
  507. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  508. ;; Browse current buffer
  509.  
  510. (defun browse-url-of-file (&optional file)
  511.   "Ask a WWW browser to display FILE.
  512. Display the current buffer's file if FILE is nil or if called
  513. interactively.  Turn the filename into a URL with function
  514. browse-url-file-url.  Pass the URL to a browser using variable
  515. `browse-url-browser-function' then run `browse-url-of-file-hook'."
  516.   (interactive)
  517.   (or file
  518.       (setq file (buffer-file-name))
  519.       (error "Current buffer has no file"))
  520.   (let ((buf (get-file-buffer file)))
  521.     (if buf
  522.     (save-excursion
  523.       (set-buffer buf)
  524.       (cond ((not (buffer-modified-p)))
  525.         (browse-url-save-file (save-buffer))
  526.         (t (message "%s modified since last save" file))))))
  527.   (funcall browse-url-browser-function (browse-url-file-url file))
  528.   (run-hooks 'browse-url-of-file-hook))
  529.  
  530. (defun browse-url-file-url (file)
  531.   "Return the URL corresponding to FILE.
  532. Use variable `browse-url-filename-alist' to map filenames to URLs.
  533. Convert EFS file names of the form /USER@HOST:PATH to ftp://HOST/PATH."
  534.   ;; URL-encode special chars, do % first
  535.   (let ((s 0))
  536.     (while (setq s (string-match "%" file s))
  537.       (setq file (replace-match "%25" t t file)
  538.         s (1+ s))))
  539.   (while (string-match "[*\"()',=;? ]" file)
  540.     (setq enc (format "%%%x" (aref file (match-beginning 0)))
  541.       file (replace-match enc t t file)))
  542.   (let ((maps browse-url-filename-alist))
  543.     (while maps
  544.       (let* ((map (car maps))
  545.          (from-re (car map))
  546.          (to-string (cdr map)))
  547.     (setq maps (cdr maps))
  548.     (and (string-match from-re file)
  549.          (setq file (replace-match to-string t t file))))))
  550.   ;; Check for EFS path
  551.   (and (string-match "^/\\([^:@]+@\\)?\\([^:]+\\):/*" file)
  552.        (setq file (concat "ftp://"
  553.               (substring file (match-beginning 2) (match-end 2))
  554.               "/" (substring file (match-end 0)))))
  555.   file)
  556.  
  557. (defun browse-url-of-buffer (&optional buffer)
  558.   "Ask a WWW browser to display BUFFER.
  559. Display the current buffer if BUFFER is nil."
  560.   (interactive)
  561.   (save-excursion
  562.     (and buffer (set-buffer buffer))
  563.     (let ((file-name
  564.        (or buffer-file-name
  565.            (and (boundp 'dired-directory) dired-directory))))
  566.       (or file-name
  567.       (progn
  568.         (or browse-url-temp-file-name
  569.         (setq browse-url-temp-file-name
  570.               (make-temp-name
  571.                (expand-file-name (buffer-name)
  572.                      (or (getenv "TMPDIR") "/tmp")))
  573.               browse-url-temp-file-list
  574.               (cons browse-url-temp-file-name
  575.                 browse-url-temp-file-list)))
  576.         (setq file-name browse-url-temp-file-name)
  577.         (write-region (point-min) (point-max) file-name nil 'no-message)))
  578.       (browse-url-of-file file-name))))
  579.  
  580. (defun browse-url-delete-temp-file (&optional temp-file-name)
  581.   ;; Delete browse-url-temp-file-name from the file system and from
  582.   ;; browse-url-temp-file-list.  If optional arg TEMP-FILE-NAME is
  583.   ;; non-nil, delete it instead, but only from the file system --
  584.   ;; browse-url-temp-file-list is not affected.
  585.   (let ((file-name (or temp-file-name browse-url-temp-file-name)))
  586.     (if (and file-name (file-exists-p file-name))
  587.     (progn
  588.       (delete-file file-name)
  589.       (if (null temp-file-name)
  590.           (setq browse-url-temp-file-list
  591.             (delete browse-url-temp-file-name
  592.                 browse-url-temp-file-list)))))))
  593.  
  594. (defun browse-url-delete-temp-file-list ()
  595.   ;; Delete all elements of browse-url-temp-file-list.
  596.   (while browse-url-temp-file-list
  597.     (browse-url-delete-temp-file (car browse-url-temp-file-list))
  598.     (setq browse-url-temp-file-list
  599.       (cdr browse-url-temp-file-list))))
  600.  
  601. (add-hook 'kill-buffer-hook 'browse-url-delete-temp-file)
  602. (add-hook 'kill-emacs-hook 'browse-url-delete-temp-file-list)
  603.  
  604. (defun browse-url-of-dired-file ()
  605.   "In Dired, ask a WWW browser to display the file named on this line."
  606.   (interactive)
  607.   (browse-url-of-file (dired-get-filename)))
  608.  
  609. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  610. ;; Browser-independant commands
  611.  
  612. ;; A generic command to call the current b-u-browser-function
  613.  
  614. (defun browse-url (&rest args)
  615.   "Ask a WWW browser to load URL.
  616. Prompts for a URL, defaulting to the URL at or before point.  Variable
  617. `browse-url-browser-function' says which browser to use."
  618.   (interactive (browse-url-interactive-arg "URL: "))
  619.   (apply browse-url-browser-function args))
  620.  
  621. (defun browse-url-at-point ()
  622.   "Ask a WWW browser to load the URL at or before point.
  623. Doesn't let you edit the URL like browse-url.  Variable
  624. `browse-url-browser-function' says which browser to use."
  625.   (interactive)
  626.   (funcall browse-url-browser-function (browse-url-url-at-point)))
  627.  
  628. ;; Define these if not already defined (XEmacs compatibility)
  629.  
  630. (eval-and-compile
  631.   (or (fboundp 'event-buffer)
  632.       (defun event-buffer (event)
  633.     (window-buffer (posn-window (event-start event))))))
  634.  
  635. (eval-and-compile
  636.   (or (fboundp 'event-point)
  637.       (defun event-point (event)
  638.     (posn-point (event-start event)))))
  639.  
  640. (defun browse-url-at-mouse (event)
  641.   "Ask a WWW browser to load a URL clicked with the mouse.
  642. The URL is the one around or before the position of the mouse click
  643. but point is not changed.  Doesn't let you edit the URL like
  644. browse-url.  Variable `browse-url-browser-function' says which browser
  645. to use."
  646.   (interactive "e")
  647.   (save-excursion
  648.     (set-buffer (event-buffer event))
  649.     (goto-char (event-point event))
  650.     (let ((url (browse-url-url-at-point)))
  651.       (if (string-equal url "")
  652.       (error "No URL found"))
  653.       (funcall browse-url-browser-function url))))
  654.  
  655. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  656. ;; Browser-specific commands
  657.  
  658. ;; --- Netscape ---
  659.  
  660. ;; Put the correct DISPLAY value in the environment for Netscape
  661. ;; launched from multi-display Emacs.
  662.  
  663. (defun browse-url-process-environment ()
  664.   (let* ((device (and (fboundp 'selected-device)
  665.               (fboundp 'device-connection)
  666.                       (selected-device)))
  667.          (display (and device (fboundp 'device-type)
  668.                        (eq (device-type device) 'x)
  669.                        (not (equal (device-connection device)
  670.                                    (getenv "DISPLAY"))))))
  671.     (if display
  672.         ;; Attempt to run on the correct display
  673.         (cons (concat "DISPLAY=" (device-connection device))
  674.               process-environment)
  675.       process-environment)))
  676.  
  677.  
  678. ;;;###autoload
  679. (defun browse-url-netscape (url &optional new-window)
  680.   "Ask the Netscape WWW browser to load URL.
  681.  
  682. Default to the URL around or before point.  The strings in variable
  683. `browse-url-netscape-arguments' are also passed to Netscape.
  684.  
  685. When called interactively, if variable `browse-url-new-window-p' is
  686. non-nil, load the document in a new Netscape window, otherwise use a
  687. random existing one.  A non-nil interactive prefix argument reverses
  688. the effect of browse-url-new-window-p.
  689.  
  690. When called non-interactively, optional second argument NEW-WINDOW is
  691. used instead of browse-url-new-window-p."
  692.   (interactive (browse-url-interactive-arg "Netscape URL: "))
  693.   (let* ((process-environment (browse-url-process-environment))
  694.          (process (apply 'start-process
  695.              (concat "netscape " url) nil
  696.              browse-url-netscape-command
  697.              (append browse-url-netscape-arguments
  698.                  (if new-window '("-noraise"))
  699.                  (list "-remote" 
  700.                        (concat "openURL(" url 
  701.                            (if new-window ",new-window")
  702.                            ")"))))))
  703.     (set-process-sentinel process
  704.        (list 'lambda '(process change)
  705.          (list 'browse-url-netscape-sentinel 'process url)))))
  706.  
  707. (defun browse-url-netscape-sentinel (process url)
  708.   "Handle a change to the process communicating with Netscape."
  709.   (or (eq (process-exit-status process) 0)
  710.       (let* ((process-environment (browse-url-process-environment)))
  711.     ;; Netscape not running - start it
  712.     (message "Starting Netscape...")
  713.     (apply 'start-process (concat "netscape" url) nil
  714.            browse-url-netscape-command
  715.            (append browse-url-netscape-arguments (list url))))))
  716.  
  717. (defun browse-url-netscape-reload ()
  718.   "Ask Netscape to reload its current document."
  719.   (interactive)
  720.   (browse-url-netscape-send "reload"))
  721.  
  722. (defun browse-url-netscape-send (command)
  723.   "Send a remote control command to Netscape."
  724.   (let* ((process-environment (browse-url-process-environment)))
  725.     (apply 'start-process "netscape" nil
  726.            browse-url-netscape-command
  727.            (append browse-url-netscape-arguments
  728.                    (list "-remote" command)))))
  729.  
  730. ;; --- Mosaic ---
  731.  
  732. ;;;###autoload
  733. (defun browse-url-mosaic (url &optional new-window)
  734.   ;; new-window ignored
  735.   "Ask the XMosaic WWW browser to load URL.
  736. Default to the URL around or before point."
  737.   (interactive (browse-url-interactive-arg "Mosaic URL: "))
  738.   (let ((pidfile (expand-file-name "~/.mosaicpid"))
  739.     pid pidbuf)
  740.     (if (file-readable-p pidfile)
  741.     (save-excursion
  742.       (find-file pidfile)
  743.       (goto-char (point-min))
  744.       (setq pid (read (current-buffer)))
  745.       (kill-buffer nil)))
  746.     (if (and pid (zerop (signal-process pid 0))) ; Mosaic running
  747.     (save-excursion
  748.       (find-file (format "/tmp/Mosaic.%d" pid))
  749.       (erase-buffer)
  750.       (insert "goto\n" url "\n")
  751.       (save-buffer)
  752.       (kill-buffer nil)
  753.       ;; Send signal SIGUSR to Mosaic
  754.       (message "Signalling Mosaic...")
  755.       (signal-process pid browse-url-usr1-signal)
  756.       ;; Or you could try:
  757.       ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
  758.       (message "Signalling Mosaic...done")
  759.       )
  760.       ;; Mosaic not running - start it
  761.       (message "Starting Mosaic...")
  762.       (apply 'start-process "xmosaic" nil "xmosaic"
  763.          (append browse-url-mosaic-arguments (list url)))
  764.       (message "Starting Mosaic...done"))))
  765.  
  766. ;; --- Grail ---
  767.  
  768. (defvar browse-url-grail
  769.   (concat (or (getenv "GRAILDIR") "~/.grail") "/user/rcgrail.py")
  770.   "*Location of Grail remote control client script `rcgrail.py'.
  771. Typically found in $GRAILDIR/rcgrail.py, or ~/.grail/user/rcgrail.py.")
  772.  
  773. ;;;###autoload
  774. (defun browse-url-grail (url)
  775.   "Ask the Grail WWW browser to load URL.
  776. Default to the URL around or before point.  Runs the program in the
  777. variable `browse-url-grail'."
  778.   (interactive (browse-url-interactive-arg "Grail URL: "))
  779.   (message "Sending URL to Grail...")
  780.   (save-excursion
  781.     (set-buffer (get-buffer-create " *Shell Command Output*"))
  782.     (erase-buffer)
  783.     ;; don't worry about this failing.
  784.     (call-process browse-url-grail nil 0 nil url)
  785.     (message "Sending URL to Grail... done")))
  786.  
  787. ;; --- Mosaic using CCI ---
  788.  
  789. (defun browse-url-cci (url &optional new-window)
  790.   "Ask the XMosaic WWW browser to load URL.
  791. Default to the URL around or before point.
  792.  
  793. This function only works for XMosaic version 2.5 or later.  You must
  794. select `CCI' from XMosaic's File menu, set the CCI Port Address to the
  795. value of variable `browse-url-CCI-port', and enable `Accept requests'.
  796.  
  797. When called interactively, if variable `browse-url-new-window-p' is
  798. non-nil, load the document in a new browser window, otherwise use a
  799. random existing one.  A non-nil interactive prefix argument reverses
  800. the effect of browse-url-new-window-p.
  801.  
  802. When called non-interactively, optional second argument NEW-WINDOW is
  803. used instead of browse-url-new-window-p."
  804.   (interactive (browse-url-interactive-arg "Mosaic URL: "))
  805.   (open-network-stream "browse-url" " *browse-url*"
  806.                browse-url-CCI-host browse-url-CCI-port)
  807.   ;; Todo: start browser if fails
  808.   (process-send-string "browse-url"
  809.                (concat "get url (" url ") output "
  810.                    (if new-window "new" "current") "\r\n"))
  811.   (process-send-string "browse-url" "disconnect\r\n")
  812.   (delete-process "browse-url"))
  813.  
  814. ;; --- IXI Mosaic ---
  815.  
  816. ;;;###autoload
  817. (defun browse-url-iximosaic (url &optional new-window)
  818.   ;; new-window ignored
  819.   "Ask the IXIMosaic WWW browser to load URL.
  820. Default to the URL around or before point."
  821.   (interactive (browse-url-interactive-arg "IXI Mosaic URL: "))
  822.   (start-process "tellw3b" nil "tellw3b"
  823.          "-service WWW_BROWSER ixi_showurl " url))
  824.  
  825. ;; --- W3 ---
  826.  
  827. ;;;###autoload
  828. (defun browse-url-w3 (url &optional new-window)
  829.   ;; new-window ignored
  830.   "Ask the w3 WWW browser to load URL.
  831. Default to the URL around or before point."
  832.   (interactive (browse-url-interactive-arg "W3 URL: "))
  833.   (w3-fetch url))
  834.  
  835. ;; --- Lynx in an xterm ---
  836.  
  837. ;;;###autoload
  838. (defun browse-url-lynx-xterm (url &optional new-window)
  839.   ;; new-window ignored
  840.   "Ask the Lynx WWW browser to load URL.
  841. Default to the URL around or before point.  A new Lynx process is run
  842. in an Xterm window."
  843.   (interactive (browse-url-interactive-arg "Lynx URL: "))
  844.   (start-process (concat "lynx" url) nil "xterm" "-e" "lynx" url))
  845.  
  846. (eval-when-compile (require 'term))
  847.  
  848. ;; --- Lynx in an Emacs "term" window ---
  849.  
  850. ;;;###autoload
  851. (defun browse-url-lynx-emacs (url &optional new-window)
  852.   ;; new-window ignored
  853.   "Ask the Lynx WWW browser to load URL.
  854. Default to the URL around or before point.  Run a new Lynx process in
  855. an Emacs buffer."
  856.   (interactive (browse-url-interactive-arg "Lynx URL: "))
  857.   (let ((system-uses-terminfo t))    ; Lynx uses terminfo
  858.     (if (fboundp 'make-term)
  859.     (let ((term-term-name "vt100"))
  860.       (set-buffer (make-term "browse-url" "lynx" nil url))
  861.       (term-mode)
  862.       (term-char-mode)
  863.       (switch-to-buffer "*browse-url*"))
  864.       (terminal-emulator "*browse-url*" "lynx" (list url)))))
  865.  
  866. (provide 'browse-url)
  867.  
  868. ;;; browse-url.el ends here
  869.